﻿namespace SERFLITEMAX20.Core
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Text.RegularExpressions;

    public class MemoryReader
    {
        private IntPtr eightBytes = Marshal.AllocHGlobal(8);
        private EventHandler ExitedEvent;
        private IntPtr hProcess = IntPtr.Zero;
        private bool isOpen;
        private Process readProcess;

        internal MemoryReader()
        {
        }

        [DllImport("advapi32.dll", CharSet=CharSet.Auto)]
        private static extern bool AdjustTokenPrivileges(IntPtr handle, bool dsall, ref TOKEN_PRIVILEGES newstate, int len, IntPtr oldstate, IntPtr retlen);
        public void Close()
        {
            if (this.hProcess == IntPtr.Zero)
            {
                throw new Exception("Process already closed.");
            }
            if (!CloseHandle(this.hProcess))
            {
                throw new Exception("CloseHandle failed.");
            }
            this.hProcess = IntPtr.Zero;
            this.isOpen = false;
            this.readProcess.Exited -= this.ExitedEvent;
            this.readProcess = null;
        }

        [DllImport("KERNEL32.DLL")]
        private static extern bool CloseHandle(IntPtr hObject);
        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern bool ConvertSecurityDescriptorToStringSecurityDescriptor(IntPtr SecurityDescriptor, int RequestedStringSDRevision, int SecurityInformation, out string TheString, out int TheStringLength);
        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor, int StringSDRevision, out IntPtr SecurityDescriptor, out int SecurityDescriptorSize);
        [DllImport("KERNEL32.DLL", SetLastError=true)]
        private static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);
        public void DumpData()
        {
            int num = 0x3ff80004;
            FileStream output = new FileStream(@".\dump.dat", FileMode.OpenOrCreate);
            BinaryWriter writer = new BinaryWriter(output);
            for (int i = 0; i <= num; i++)
            {
                writer.Write(this.ReadBuffer(i, 0x960));
                i += 0x960;
            }
            writer.Close();
            output.Close();
        }

        public SortedList<string, string> DumpString(int ptr, int from, int to, int size)
        {
            Debug.WriteLine("---------------------------------");
            SortedList<string, string> list = new SortedList<string, string>();
            for (int i = from; i <= to; i++)
            {
                string key = this.ReadString(ptr + i, size);
                if (!list.ContainsKey(key))
                {
                    string str2 = "base: " + ptr.ToString() + " offset: " + i.ToString() + " value: " + key;
                    list.Add(key, str2);
                    Debug.WriteLine(str2);
                }
            }
            Debug.WriteLine("---------------------------------");
            return list;
        }

        public SortedList<string, string> DumpString(int ptr, int from, int to, int from_offset, int to_offset, int size)
        {
            int num;
            int num2;
            string str;
            string str2;
            Debug.WriteLine("---------------------------------");
            SortedList<string, string> list = new SortedList<string, string>();
            for (num = from; num <= to; num++)
            {
                num2 = this.ReadInteger(ptr + num);
                if (num2 > 0)
                {
                    for (int i = from_offset; i <= to_offset; i++)
                    {
                        str = this.ReadString(num2 + i, size);
                        if ((Regex.IsMatch(str, "^[a-zA-Z]+$") && (str.Length > 3)) && !list.ContainsKey(str))
                        {
                            str2 = "base: " + ptr.ToString() + " offset: " + num.ToString() + " sub_offset: " + i.ToString() + " value: " + str;
                            list.Add(str, str2);
                            Debug.WriteLine(str2);
                        }
                    }
                }
            }
            for (num = from; num <= to; num++)
            {
                num2 = this.ReadInteger(ptr + num);
                str = this.ReadString(num2, size);
                if ((Regex.IsMatch(str, "^[a-zA-Z]+$") && (str.Length > 3)) && !list.ContainsKey(str))
                {
                    str2 = "base: " + ptr.ToString() + " offset: " + num.ToString() + " value: " + str;
                    list.Add(str, str2);
                    Debug.WriteLine(str2);
                }
            }
            for (num = from; num <= to; num++)
            {
                str = this.ReadString(ptr + num, size);
                if ((Regex.IsMatch(str, "^[a-zA-Z]+$") && (str.Length > 3)) && !list.ContainsKey(str))
                {
                    str2 = "base: " + ptr.ToString() + " offset: " + num.ToString() + " value: " + str;
                    list.Add(str, str2);
                    Debug.WriteLine(str2);
                }
            }
            Debug.WriteLine("---------------------------------");
            return list;
        }

        ~MemoryReader()
        {
            if (this.isOpen)
            {
                this.Close();
            }
            Marshal.FreeHGlobal(this.eightBytes);
        }

        public void FindString(string pValue)
        {
            int num = 0x7ff00008;
            int num2 = 0;
            for (int i = 0; i <= num; i++)
            {
                int missed = 0;
                string input = this.ReadString(i, 0x40, out missed);
                num2++;
                if (num2 > 0xf4240)
                {
                    Console.WriteLine(i);
                    num2 = 0;
                }
                if (input != null)
                {
                    if (Regex.IsMatch(input, "^[a-zA-Z]+$") && (input.Length > 3))
                    {
                        if (input.IndexOf("Wooden") != -1)
                        {
                            Console.WriteLine(i + " " + input);
                        }
                        Debug.WriteLine(i + " " + input);
                    }
                    else
                    {
                        i = missed + i;
                    }
                }
            }
        }

        public int GetBaseAddrFromTLS(int TLSSlotPtr, int GuidOffset, int MainTableOffset, out long pGuid)
        {
            pGuid = 0L;
            int num = this.ReadInteger(TLSSlotPtr);
            foreach (ProcessThread thread in this.readProcess.Threads)
            {
                IntPtr hThread = OpenThread(0x40, false, thread.Id);
                if (hThread.ToInt32() > 0)
                {
                    uint num2;
                    THREADINFOCLASS structure = new THREADINFOCLASS();
                    IntPtr pOutput = Marshal.AllocHGlobal(80);
                    int num3 = NtQueryInformationThread(hThread, 0, pOutput, (uint) Marshal.SizeOf(structure), out num2);
                    Marshal.PtrToStructure(pOutput, structure);
                    Marshal.FreeHGlobal(hThread);
                    CloseHandle(hThread);
                    if (num3 == 0)
                    {
                        int num4 = this.ReadInteger(structure.TebBaseAddress + 0x2c);
                        if (num4 != 0)
                        {
                            int num5 = this.ReadInteger((num * 4) + num4);
                            int num6 = this.ReadInteger(num5 + 8);
                            pGuid = this.ReadLong(num5 + 0x10);
                            if ((num6 != 0) && (pGuid > 0L))
                            {
                                return num6;
                            }
                        }
                    }
                }
            }
            return 0;
        }

        [DllImport("user32.dll")]
        public static extern int GetForegroundWindow();
        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern bool GetSecurityDescriptorDacl(IntPtr SecurityDescriptor, out int DACLPresent, out IntPtr DACL, out int DACLDefaulted);
        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern uint GetSecurityInfo(IntPtr handle, int ObjectType, int SecurityInfo, IntPtr pSidOwner, IntPtr pSidGroup, out IntPtr pDacl, IntPtr pSacl, out IntPtr pSecurityDescriptor);
        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, byte[] Buffer, uint TokenInformationLength, out uint ReturnLength);
        [DllImport("user32.dll")]
        public static extern int GetWindowText(int hWnd, StringBuilder text, int count);
        [DllImport("advapi32.dll", CharSet=CharSet.Auto)]
        public static extern bool LookupPrivilegeValue(string sysname, string privname, out ulong luid);
        [DllImport("ntdll.dll", SetLastError=true)]
        private static extern int NtQueryInformationThread(IntPtr hThread, uint ThreadInformationClass, IntPtr pOutput, uint ThreadInformationLength, out uint ReturnLength);
        private bool OpenGameProcess()
        {
            this.hProcess = OpenProcess(0x1f0fff, false, this.readProcess.Id);
            if (!this.OpenGameProcessEx())
            {
                Console.WriteLine("First open failed, tweaking game security");
                this.hProcess = this.TweakACL();
                if (this.hProcess == IntPtr.Zero)
                {
                    return false;
                }
                return this.OpenGameProcessEx();
            }
            return true;
        }

        private bool OpenGameProcessEx()
        {
            if (this.hProcess != IntPtr.Zero)
            {
                uint num;
                ulong num2;
                IntPtr ptr;
                byte[] buffer = new byte[0x100];
                if (!LookupPrivilegeValue("", "SeDebugPrivilege", out num2))
                {
                    return false;
                }
                if (!OpenProcessToken(this.hProcess, 40, out ptr))
                {
                    return false;
                }
                if (!GetTokenInformation(ptr, TOKEN_INFORMATION_CLASS.TokenPrivileges, buffer, 0x100, out num))
                {
                    return false;
                }
                int num4 = BitConverter.ToInt32(buffer, 0);
                for (int i = 0; i < num4; i++)
                {
                    int startIndex = 4 + (12 * i);
                    ulong num6 = BitConverter.ToUInt64(buffer, startIndex);
                    if (num6 == num2)
                    {
                        TOKEN_PRIVILEGES newstate = new TOKEN_PRIVILEGES();
                        newstate.PrivilegeCount = 1;
                        newstate.Luid = num6;
                        newstate.Attributes = 4;
                        if (!AdjustTokenPrivileges(ptr, false, ref newstate, Marshal.SizeOf(newstate), IntPtr.Zero, IntPtr.Zero))
                        {
                            return false;
                        }
                    }
                }
                CloseHandle(ptr);
                return true;
            }
            return false;
        }

        [DllImport("KERNEL32.DLL", SetLastError=true)]
        private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);
        public void OpenProcessByName(string processName)
        {
            if (this.isOpen)
            {
                throw new Exception("Process already opened.");
            }
            Process[] processesByName = Process.GetProcessesByName(processName);
            if (processesByName.Length <= 0)
            {
                throw new Exception("Cannot find process.");
            }
            this.readProcess = processesByName[0];
            this.isOpen = this.OpenGameProcess();
            if (this.isOpen)
            {
                this.readProcess.Exited += (this.ExitedEvent = new EventHandler(this.ProcessExited));
            }
        }

        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
        [DllImport("KERNEL32.DLL", SetLastError=true)]
        private static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, int dwThreadId);
        [DllImport("KERNEL32.DLL")]
        private static extern int Process32First(IntPtr handle, ref PROCESSENTRY32 pe);
        [DllImport("KERNEL32.DLL")]
        private static extern int Process32Next(IntPtr handle, ref PROCESSENTRY32 pe);
        private void ProcessExited(object sender, EventArgs e)
        {
            if (sender == this.readProcess)
            {
                this.isOpen = false;
            }
        }

        public byte[] ReadBuffer(int Address, int bytes)
        {
            IntPtr ptr = Marshal.AllocHGlobal(bytes);
            IntPtr zero = IntPtr.Zero;
            ReadProcessMemory(this.hProcess, new IntPtr(Address), ptr, bytes, ref zero);
            byte[] destination = new byte[bytes];
            Marshal.Copy(ptr, destination, 0, bytes);
            Marshal.FreeHGlobal(ptr);
            return destination;
        }

        public byte ReadByte(int Address)
        {
            IntPtr zero = IntPtr.Zero;
            ReadProcessMemory(this.hProcess, new IntPtr(Address), this.eightBytes, 1, ref zero);
            return Marshal.ReadByte(this.eightBytes);
        }

        public float ReadFloat(int Address)
        {
            IntPtr zero = IntPtr.Zero;
            ReadProcessMemory(this.hProcess, new IntPtr(Address), this.eightBytes, 4, ref zero);
            byte[] destination = new byte[4];
            Marshal.Copy(this.eightBytes, destination, 0, 4);
            return BitConverter.ToSingle(destination, 0);
        }

        public int ReadInteger(int Address)
        {
            IntPtr zero = IntPtr.Zero;
            ReadProcessMemory(this.hProcess, new IntPtr(Address), this.eightBytes, 4, ref zero);
            return Marshal.ReadInt32(this.eightBytes);
        }

        public long ReadLong(int Address)
        {
            IntPtr zero = IntPtr.Zero;
            ReadProcessMemory(this.hProcess, new IntPtr(Address), this.eightBytes, 8, ref zero);
            return Marshal.ReadInt64(this.eightBytes);
        }

        [DllImport("KERNEL32.dll")]
        private static extern int ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr buffer, int size, ref IntPtr lpNumberOfBytesRead);
        public string ReadString(int Address, int bytes)
        {
            int missed = 0;
            return this.ReadString(Address, bytes, out missed);
        }

        public string ReadString(int Address, int bytes, out int missed)
        {
            missed = 0;
            IntPtr ptr = Marshal.AllocHGlobal(bytes);
            IntPtr zero = IntPtr.Zero;
            ReadProcessMemory(this.hProcess, new IntPtr(Address), ptr, bytes, ref zero);
            byte[] destination = new byte[bytes];
            Marshal.Copy(ptr, destination, 0, bytes);
            Marshal.FreeHGlobal(ptr);
            string str = new UTF8Encoding().GetString(destination);
            int index = str.IndexOf("\0");
            if (index != -1)
            {
                int count = str.Length - index;
                str = str.Remove(index, count);
                missed = str.Length;
            }
            return str;
        }

        public string ReadString(int ptr, int offset, int sub_offset, int size)
        {
            string str = null;
            int num = this.ReadInteger(ptr + offset);
            if (num != 0)
            {
                str = this.ReadString(num + sub_offset, size);
            }
            return str;
        }

        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern uint SetSecurityInfo(IntPtr handle, int ObjectType, int SecurityInfo, IntPtr pSidOwner, IntPtr pSidGroup, IntPtr pDacl, IntPtr pSacl);
        [DllImport("KERNEL32.DLL")]
        private static extern int Thread32First(IntPtr handle, ref THREADENTRY32 pe);
        [DllImport("KERNEL32.DLL")]
        private static extern int Thread32Next(IntPtr handle, ref THREADENTRY32 pe);
        private IntPtr TweakACL()
        {
            IntPtr zero = IntPtr.Zero;
            IntPtr handle = OpenProcess(0x40000, false, this.readProcess.Id);
            if (!(handle != IntPtr.Zero))
            {
                return handle;
            }
            if (SetSecurityInfo(handle, 6, 0x20000004, IntPtr.Zero, IntPtr.Zero, zero, IntPtr.Zero) != 0)
            {
                CloseHandle(handle);
                return IntPtr.Zero;
            }
            CloseHandle(handle);
            return OpenProcess(0x1f0fff, false, this.readProcess.Id);
        }

        public bool TweakMyACL()
        {
            IntPtr ptr;
            IntPtr ptr2;
            IntPtr handle = OpenProcess(0x1f0fff, false, Process.GetCurrentProcess().Id);
            if (GetSecurityInfo(handle, 6, 4, IntPtr.Zero, IntPtr.Zero, out ptr2, IntPtr.Zero, out ptr) == 0)
            {
                IntPtr ptr3;
                IntPtr ptr4;
                IntPtr ptr5;
                int num;
                int num2;
                string str;
                if (GetSecurityInfo(handle, 6, 4, IntPtr.Zero, IntPtr.Zero, out ptr4, IntPtr.Zero, out ptr3) != 0)
                {
                    return false;
                }
                if (!ConvertSecurityDescriptorToStringSecurityDescriptor(ptr3, 1, 4, out str, out num))
                {
                    return false;
                }
                if (ConvertStringSecurityDescriptorToSecurityDescriptor("D:(D;;RPWD;;;WD)" + str.Substring(2), 1, out ptr5, out num2))
                {
                    IntPtr ptr6;
                    int num3;
                    int num4;
                    if (!GetSecurityDescriptorDacl(ptr5, out num3, out ptr6, out num4))
                    {
                        return false;
                    }
                    if (SetSecurityInfo(handle, 6, 4, IntPtr.Zero, IntPtr.Zero, ptr6, IntPtr.Zero) != 0)
                    {
                        return false;
                    }
                    return true;
                }
            }
            return false;
        }

        public bool WowActive()
        {
            bool flag = false;
            StringBuilder text = new StringBuilder(0x100);
            if (GetWindowText(GetForegroundWindow(), text, 0x100) > 0)
            {
                flag = text.ToString() == "World of Warcraft";
            }
            return flag;
        }

        public IntPtr Handle
        {
            get
            {
                return this.hProcess;
            }
        }

        public bool IsOpen
        {
            get
            {
                return this.isOpen;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct PROCESSENTRY32
        {
            public uint dwSize;
            public uint cntUsage;
            public uint th32ProcessID;
            public IntPtr th32DefaultHeapID;
            public uint th32ModuleID;
            public uint cntThreads;
            public uint th32ParentProcessID;
            public uint pcPriClassBase;
            public uint dwFlags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
            public string szExeFile;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal protected struct THREADENTRY32
        {
            public uint dwSize;
            public uint cntUsage;
            public uint th32ThreadID;
            public uint th32OwnerProcessID;
            public uint tpBasePri;
            public uint tpDeltaPri;
            public uint dwFlags;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal protected class THREADINFOCLASS
        {
            public int ExitStatus;
            public int TebBaseAddress;
            public int UniqueProcess;
            public int UniqueThread;
            public int AffinityMask;
            public int Priority;
            public int BasePriority;
        }

        public enum TOKEN_INFORMATION_CLASS
        {
            MaxTokenInfoClass = 0x1d,
            TokenAccessInformation = 0x16,
            TokenAuditPolicy = 0x10,
            TokenDefaultDacl = 6,
            TokenElevation = 20,
            TokenElevationType = 0x12,
            TokenGroups = 2,
            TokenGroupsAndPrivileges = 13,
            TokenHasRestrictions = 0x15,
            TokenImpersonationLevel = 9,
            TokenIntegrityLevel = 0x19,
            TokenLinkedToken = 0x13,
            TokenLogonSid = 0x1c,
            TokenMandatoryPolicy = 0x1b,
            TokenOrigin = 0x11,
            TokenOwner = 4,
            TokenPrimaryGroup = 5,
            TokenPrivileges = 3,
            TokenRestrictedSids = 11,
            TokenSandBoxInert = 15,
            TokenSessionId = 12,
            TokenSessionReference = 14,
            TokenSource = 7,
            TokenStatistics = 10,
            TokenType = 8,
            TokenUIAccess = 0x1a,
            TokenUser = 1,
            TokenVirtualizationAllowed = 0x17,
            TokenVirtualizationEnabled = 0x18
        }

        [StructLayout(LayoutKind.Sequential, Pack=1)]
        private struct TOKEN_PRIVILEGES
        {
            public int PrivilegeCount;
            public ulong Luid;
            public int Attributes;
        }
    }
}

